import java.util.LinkedList ;
import java.io.FileWriter ;
import java.io.PrintWriter ;
import java.io.BufferedReader ;
import java.io.InputStreamReader ;
import javax.swing.* ;
import java.awt.* ;
import java.awt.event.* ;

public class ExperimentAnalyzer extends ParameterFramework implements ActionListener {
    private INeuron [ ] neurons ;
    private final INeuralNetExperiment e ;
    private static Experimenter experimenter = null ;
    private TextArea textPane = null ;
    private JFrame window = null ;
    private static double SYNC_THRESHOLD = .2 ;
    private static double FIRING_THRESHOLD = .5 ;
    private static int ACTIVE_TIME = 500 ;
    
    
    private static final WindowAdapter ON_CLOSE = new WindowAdapter( ) {
        public void windowClosing( WindowEvent e ) {
            if ( experimenter != null ) {
                experimenter.enableGo( ) ;
            }
            e.getWindow().dispose( ) ;
        }
    } ;
    
    private static int getInt( String msg , int min , int max ) throws CancelClicked {
        int choice = min - 1 ;
        String s = null ;
        
        do {
            try {
                s = getString( msg );
                if ( s == null ) {
                    throw new CancelClicked();
                }
                choice = Integer.parseInt( s ) ;
            } catch ( CancelClicked e ) {
                throw e;
            } catch ( Exception e2 ) {
            }
        } while ( choice < min || choice > max ) ;
        return choice ;
    }
    
    private static String getString( String prompt ) {
        return getString( prompt , "" ) ;
    }
    
    private static String getString( String prompt , String def ) {
        return ( String ) JOptionPane.showInputDialog( null , prompt , "" , JOptionPane.PLAIN_MESSAGE , null , null , def ) ;
    }
    
    private int number( INeuron n ) {
        int i ;
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            if ( n == neurons [ i ] ) {
                return i + 1 ;
            }
        }
        return -1 ;
    }
    
    private void disp( LinkedList<String> out ) {
        if ( textPane != null ) {
            for ( String s : out ) {
                println( s ) ;
            }
        }
    }
    
    private void println( String out ) {
        textPane.append( out + "\n" ) ;
    }
    
    // returns the average membrane potential of the neuron over the
    // past deltaT time steps
    public static double getAvg( INeuron n , int deltaT ) {
        double result = 0 ;
        int time = n.getTime( ) , t ;
        
        for ( t = Math.max( 0 , time - deltaT ) ; t < time ; t ++ ) {
            result += n.getPotential( t ) ;
        }
        result /= ( time - Math.max( 0 , time - deltaT ) ) ;
        return result ;
    }
    
    // Working definition:  A neuron is synchronized if it is synchronized
    // with some other neuron beyond SYNC_THRESHOLD.
    public boolean isSynchronized( INeuron n ) {
        int i ;
        INeuron m ;
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            m = neurons [ i ] ;
            if ( m != n ) {
                if ( getCorrelation( m , n ) >= SYNC_THRESHOLD ) {
                    return true ;
                }
            }
        }
        return false ;
    }
    
    // counts neurons that are active and synchronized
    public int numSynchronized( ) {
        int i , count = 0 ;
        
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            if ( isActive( neurons [ i ] ) && isSynchronized( neurons [ i ] ) ) {
                count ++ ;
            }
        }
        return count ;
    }
    
    // returns true if a neuron has fired within the last ACTIVE_TIME
    private boolean isActive( INeuron n ) {
        int t , stopT = n.getTime( ) ;
        for ( t = Math.max( 0 , stopT - ACTIVE_TIME ) ; t < stopT ; t ++ ) {
            if ( n.getPotential( t ) > FIRING_THRESHOLD ) {
                return true ;
            }
        }
        return false ;
    }
    
    // lists neurons that are synchronized and active
    private void listSynchronizedNeurons( ) {
        int i , count = 0 ;
        String s = new String( ) ;
        println( "The following neurons are synchronized:" ) ;
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            if ( count % 10 == 0 ) {
                if ( ! s.equals( "" ) ) {
                    println( s ) ;
                }
                s = new String( ) ;
            }
            if ( isActive( neurons [ i ] ) && isSynchronized( neurons [ i ] ) ) {
                count ++ ;
                s += "" + ( i + 1 ) + ", " ;
            }
        }
        if ( ! s.equals( "" ) ) {
            println( s ) ;
        }
    }
    
    public static double getVariance( INeuron n , int deltaT ) {
        double result = 0 ;
        double mean = getAvg( n , deltaT ) ;
        int time = n.getTime( ) , t , tStart = Math.max( 0 , time - deltaT ) ;
        
        for ( t = tStart ; t < time ; t ++ ) {
            result += Math.pow( n.getPotential( t ) - mean , 2 ) ;
        }
        return result / ( time - tStart ) ;
    }
    
    public static double getSpikeCount( INeuron n , int deltaT ) {
        int result = 0 ;
        int time = n.getTime( ) , t ;
        double oldV , v = 0 ;
        
        for ( t = Math.max( 0 , time - deltaT ) ; t < time ; t ++ ) {
            oldV = v ;
            v = n.getPotential( t ) ;
            if ( v >= FIRING_THRESHOLD && oldV < FIRING_THRESHOLD ) {
                result ++ ;
            }
        }
        return result ;
    }
    
    // creates a graph between times t1 and t2 with a point for each time
    // a neuron fires an action potential
    public void graphFiring( int t1 , int t2 ) {
        int tStart = Math.min( t1 , t2 ) ;
        int tStop = Math.max( t1 , t2 ) ;
        int i , t ;
        PointPlot p ;
        double v = 0 , oldV ;
        INeuron n ;
        LinkedList<PointPlot> plots = new LinkedList<PointPlot> ( ) ;
        
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            p = new PointPlot( ) ;
            p.id = "" + ( i + 1 ) ;
            n = neurons [ i ] ;
            v = 0 ;
            for ( t = tStart ; t < tStop ; t ++ ) {
                oldV = v ;
                v = n.getPotential( t ) ;
                if ( v >= FIRING_THRESHOLD && oldV < FIRING_THRESHOLD ) {
                    p.add( new OrderedPair( t , i + 1 ) , PointPlot.SQUARE ) ;
                }
            }
            p.isVisible = false ;
            plots.add( p ) ;
        }
        new FiringGraph( plots , "Neuron Firings From Time " + tStart + " to " + tStop + "." ) ;
    }
    
    public static double getCorrelation( INeuron n1 , INeuron n2 ) {
        double n1Bar = getAvg( n1 , 500 ) ;
        double n2Bar = getAvg( n2 , 500 ) ;
        int t , time = n1.getTime( ) ;
        double total = 0 ;
        int tSteps = Math.min( time , 500 ) ;
        double covariance ;
        
        for ( t = time - tSteps ; t < time ; t ++ ) {
            total += ( n1.getPotential( t ) - n1Bar ) * ( n2.getPotential( t ) - n2Bar ) ;
        }
        covariance = total / tSteps ;
        return covariance / Math.sqrt( getVariance( n1 , 500 ) * getVariance( n2 , 500 ) ) ;
    }
    
    private LinkedList<String> showCorrelations( INeuron n ) {
        LinkedList<String> out = new LinkedList<String> ( ) ;
        int i ;
        INeuron m ;
        double corr ;
        
        out.add( "Neuron " + number( n ) + " is correlated with the following neurons:" ) ;
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            m = neurons [ i ] ;
            corr = getCorrelation( n , m ) ;
            if ( corr >= SYNC_THRESHOLD ) {
                out.add( "  " + number( m ) + "   (" + corr + ")" ) ;
            }
        }
        return out ;
    }
    
    private LinkedList<String> showSpikeInfo( INeuron n ) {
        LinkedList<String> out = new LinkedList<String> ( ) ;
        out.add( "Neuron " + number( n ) + " has fired a total of "
                + getSpikeCount( n , n.getTime( ) ) + " action potentials," ) ;
        out.add( "  including " + getSpikeCount( n , 500 ) + " in the last "
                + Math.min( 500 , n.getTime( ) ) + " timesteps." ) ;
        out.add( "It last fired one at time " + n.lastSpike( ) + "." ) ;
        return out ;
    }
    
    
    private LinkedList<String> showAvg( INeuron n ) {
        LinkedList<String> out = new LinkedList<String> ( ) ;
        out.add( "Neuron " + number( n ) + " has had an average value of "
                + getAvg( n , 500 ) ) ;
        out.add( "  and a variance of " + getVariance( n , 500 ) ) ;
        out.add( "  over the last " + Math.min( 500 , n.getTime( ) ) + " timesteps." ) ;
        return out ;
    }
    
    private LinkedList<String> showPosition( INeuron n ) {
        LinkedList<String> out = new LinkedList<String> ( ) ;
        out.add( "Neuron " + number( n ) + " is at " + n.getPlace( ) ) ;
        return out ;
    }
    
    private LinkedList<String> showSynapses( INeuron n ) {
        LinkedList<String> out = new LinkedList<String> ( ) ;
        int i ;
        
        out.add( "Neuron " + number( n ) + " receives input from:" ) ;
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            if ( neurons[i].hasSynapseTo( n ) ) {
                out.add( "  " + ( i + 1 ) + "   (" + neurons[i].getStrengthOfSynapseTo( n ) + ")" ) ;
            }
        }
        
        out.add( "Neuron " + number( n ) + " sends output to:" ) ;
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            if ( neurons[i].hasSynapseFrom( n ) ) {
                out.add( "  " + ( i + 1 ) + "   (" + neurons[i].getStrengthOfSynapseFrom( n ) + ")" ) ;
            }
        }
        
        return out ;
    }
    
    private LinkedList<String> showMostCorrelated( ) {
        int i , j , most1 = 0 , most2 = 0 ;
        INeuron n , m ;
        double corr = Double.NEGATIVE_INFINITY , temp ;
        LinkedList<String> out = new LinkedList<String> ( ) ;
        
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            n = neurons [ i ] ;
            
            // only check for correlation if n has fired recently
            if ( n.lastSpike( ) > Math.max( 0 , n.getTime( ) - 1000 ) ) {
                for ( j = i + 1 ; j < neurons.length ; j ++ ) {
                    m = neurons [ j ] ;
                    // ditto for m
                    if ( m.lastSpike( ) > Math.max( 0 , n.getTime( ) - 1000 ) ) {
                        temp = getCorrelation( n , neurons [ j ] ) ;
                        if ( temp > corr && ( ! Double.isInfinite( temp ) ) ) {
                            corr = temp ;
                            most1 = i ;
                            most2 = j ;
                        }
                    }
                }
            }
        }
        if ( corr == Double.NEGATIVE_INFINITY ) {
            out.add( "No neurons have fired recently, so no correlations." ) ;
        } else {
            out.add( "The most correlated neurons are " + ( most1 + 1 ) + " and " + ( most2 + 1 ) + ","
                    + " at " + corr + "." ) ;
        }
        
        return out ;
    }
    
    public static void saveExperimentAsCSV( INeuralNetExperiment e , String filename ) {
        PrintWriter out = null ;
        LinkedList<INeuron> n ;
        int i , tstop ;
        String data ;
        INeuron firstNeuron ;
        
        try {
            out = new PrintWriter( new FileWriter( filename ) ) ;
        } catch ( Exception ex ) {
            System.out.println( "Unable to create file." ) ;
            return ;
        }
        if ( out != null ) {
            n = e.getNeurons( ) ;
            if ( n.size( ) > 0 ) {
                firstNeuron = n.getFirst( ) ;
                tstop = firstNeuron.getTime( ) ;
                for ( i = 0 ; i < tstop ; i ++ ) {
                    data = "" + i ;
                    for ( INeuron m : n ) {
                        data += "," + m.getPotential( i ) ;
                    }
                    out.println( data ) ;
                }
            }
            out.close( ) ;
        }
    }
    
    private void examineANeuron( ) {
        int nId ;
        INeuron n ;
        try{
            nId = getInt( "Which neuron?  (1-" + neurons.length +")  " , 1 , neurons.length ) ;
        } catch ( CancelClicked e ) {
            return ;
        }
        n = neurons [ nId - 1 ] ;
        
        disp( showPosition( n ) ) ;
        disp( showSpikeInfo( n ) ) ;
        disp( showAvg( n ) ) ;
        disp( showCorrelations( n ) ) ;
        disp( showSynapses( n ) ) ;
        println( "Integrated Synaptic Strength in of neuron " + nId + " is " + getSynapticStrengthIn( n ) + "." ) ;
        println( "Integrated Synaptic Strength out of neuron " + nId + " is " + getSynapticStrengthOut( n ) + "." ) ;
        
    }
    
    // integrated synaptic strength
    private double getSynapticStrengthIn( INeuron n ) {
        double s = 0 ;
        int i ;
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            if ( neurons[i].hasSynapseTo( n ) ) {
                s += neurons[i].getStrengthOfSynapseTo( n ) ;
            }
        }
        return s ;
    }
    
    
    // integrated synaptic strength
    private double getSynapticStrengthOut( INeuron n ) {
        double s = 0 ;
        int i ;
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            if ( neurons[i].hasSynapseFrom( n ) ) {
                s += neurons[i].getStrengthOfSynapseFrom( n ) ;
            }
        }
        return s ;
    }
    
    // we define a neuron as being active if it has fired within the last dt
    // time steps
    private void graphNumActiveBetween( int t1 , int t2 , int dt ) {
        int tStart = Math.min( t1 , t2 ) ;
        int tStop = Math.max( t1 , t2 ) ;
        double [ ] t = new double [ tStop - tStart ] ;
        double [ ] y = numActiveBetween( tStart , tStop , dt ) ;
        Graph g = new Graph( ) ;
        int i ;
        
        for ( i = 0 ; i < tStop - tStart ; i ++ ) {
            t [ i ] = i + tStart ;
        }
        
        g.addCurve( t , y , null , true ) ;
        g.autoWindow( ) ;
        g.autoLabel( ) ;
        g.makeWindow( 640 , 480 , Graph.NO_EXIT_ON_CLOSE , "Active Neurons vs Time" ) ;
    }
    
    // neuron is defined as active if has fired within the last dt
    public double [ ] numActiveBetween( int t1 , int t2 , int dt ) {
        int tStart = Math.min( t1 , t2 ) ;
        int tStop = Math.max( t1 , t2 ) ;
        double [ ] y = new double [ tStop - tStart ] ;
        int i , t3 , tPrime , j , num ;
        
        for ( i = 0 ; i < tStop - tStart ; i ++ ) {
            t3 = i + tStart ;
            num = 0 ;
            for ( j = 0 ; j < neurons.length ; j ++ ) {
                for ( tPrime = t3 - dt ; tPrime <= t3 ; tPrime ++ ) {
                    if ( neurons[j].getPotential( tPrime ) >= FIRING_THRESHOLD ) {
                        num ++ ;
                        break ;
                    }
                }
            }
            y [ i ] = num ;
        }
        return y ;
    }
    
    // graphs strength of synapses LEAVING a neuron
    // if neuron is not active:  cross
    // if neuron is synchronized:  circle
    // if neuron is active but not synchronized:  square
    public void showSynapticStrengthGraph( ) {
        PointPlot p = new PointPlot( ) ;
        Graph g ;
        int i , shape ;
        int numBiased = neurons.length ;
        
        try {
            numBiased = Integer.parseInt( e.getParam( "numBiased" ) ) ;
        } catch ( Exception ex ) {
        }
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            if ( ! isActive( neurons [ i ] ) ) {
                shape = PointPlot.CROSS ;
            } else if ( isSynchronized( neurons [ i ] ) ) {
                shape = PointPlot.CIRCLE ;
            } else {
                shape = PointPlot.SQUARE ;
            }
            p.add( new OrderedPair( i , getSynapticStrengthOut( neurons [ i ] ) ) , shape ) ;
        }
        g = new Graph( ) ;
        g.add( p ) ;
        g.autoWindow( ) ;
        g.autoLabel( ) ;
        g.makeWindow( 640 , 480 , Graph.NO_EXIT_ON_CLOSE , "Synapse Strength vs Neuron Index" ) ;
    }
    
    public void makeNewWindow( ) {
        int tMax = neurons[0].getTime( ) ;
        try{
            int t1 = getInt( "Start time (0-" + tMax +"):  " , 0 , tMax ) ;
            int t2 = getInt( "Stop time (" + t1 + "-" + tMax + "):  " , t1 , tMax ) ;
            new ExperimenterResults( e.getCurves( t1 , t2 ) , "Times " + t1 + " - " + t2 + "." ) ;
        } catch ( CancelClicked e ) {
            return ;}
    }
    
    public void graphNumActive( ) {
        int tMax = neurons[0].getTime( ) ;
        try {
            int t1 = getInt( "Start time (0-" + tMax +"):  " , 0 , tMax ) ;
            int t2 = getInt( "Stop time (" + t1 + "-" + tMax + "):  " , t1 , tMax ) ;
            graphNumActiveBetween( t1 , t2 , 100 ) ;
        } catch ( CancelClicked e ) {
            return ;}
    }
    
    public void showAvgDist( ) {
        int total = neurons.length * ( neurons.length - 1 ) ;
        double dist = 0 ;
        int i , j ;
        String temp ;
        int numBiased ;
        
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            for ( j = 0 ; j < neurons.length ; j ++ ) {
                if ( i != j ) {
                    dist += neurons[i].dist( neurons [ j ] ) ;
                }
            }
        }
        println( "The average distance between neurons is " + dist / total + "." ) ;
        
        temp = e.getParam( "numBiased" ) ;
        try {
            numBiased = Integer.parseInt( temp ) ;
            dist = 0 ;
            for ( i = 0 ; i < numBiased ; i ++ ) {
                for ( j = 0 ; j < numBiased ; j ++ ) {
                    if ( i != j ) {
                        dist += neurons[i].dist( neurons [ j ] ) ;
                    }
                }
            }
            println( "The average distance between biased neurons is " + dist / ( numBiased * ( numBiased - 1 ) ) + "." ) ;
        } catch ( Exception ex ) {
        }
    }
    
    public void showSynCount( ) {
        int count = 0 ;
        int i , j , numBiased;
        
        for ( i = 0 ; i < neurons.length ; i ++ ) {
            count += neurons[i].getNumSynapses( ) ;
        }
        println( "Total of " + count + " synapses, for an average of " + ( ( double ) count ) / neurons.length + " synapses per neuron. " ) ;
        try {
            numBiased = Integer.parseInt( e.getParam( "numBiased" ) ) ;
            if ( numBiased < neurons.length ) {
                count = 0 ;
                for ( i = 0 ; i < numBiased ; i ++ ) {
                    for ( j = numBiased ; j < neurons.length ; j ++ ) {
                        if ( neurons[i].hasSynapseTo( neurons [ j ] ) ) {
                            count ++ ;
                        }
                    }
                }
                println( "A " + numBiased + " biased neuron sends to " + ( ( double ) count ) / ( neurons.length - numBiased ) + " unbiased neurons on average." ) ;
            }
            count = 0 ;
            for ( i = 0 ; i < numBiased ; i ++ ) {
                for ( j = 0 ; j < numBiased ; j ++ ) {
                    if ( neurons[i].hasSynapseTo( neurons [ j ] ) ) {
                        count ++ ;
                    }
                }
            }
            println( "A biased neuron sends to " + ( ( double ) count ) / numBiased + " other biased neurons on average." ) ;
        } catch ( Exception ex ) {
        }
    }
    
    public void setParameters( ) {
        ParameterWindow.configure( this , "Set Analyzer Parameters" ) ;
    }
    
    public void run( ) {
        javax.swing.SwingUtilities.invokeLater( new Runnable( ) {
            public void run( ) {
                runNotThreadSafe( ) ;
            }
        } ) ;
    }
    
    private void runNotThreadSafe( ) {
        int choice ;
        String filename ;
        window = new JFrame( "Experiment Analyzer" ) ;
        window.addWindowListener( ON_CLOSE ) ;
        JPanel content = new JPanel( new BorderLayout( ) ) ;
        JPanel menuPane = new JPanel( new GridLayout( 0 , 1 ) ) ;
        JButton button ;
        
        textPane = new TextArea( ) ;
        textPane.setEditable( true ) ;
        
        button = new JButton( "Close Analyzer" ) ;
        button.setActionCommand( "close" ) ;
        button.addActionListener( this ) ;
        menuPane.add( button ) ;
        
        button = new JButton( "Save as .csv" ) ;
        button.setActionCommand( "csv" ) ;
        button.addActionListener( this ) ;
        menuPane.add( button ) ;
        
        button = new JButton( "Examine a Neuron" ) ;
        button.setActionCommand( "examine" ) ;
        button.addActionListener( this ) ;
        menuPane.add( button ) ;
        
        button = new JButton( "New Graph Window" ) ;
        button.setActionCommand( "new graph" ) ;
        button.addActionListener( this ) ;
        menuPane.add( button ) ;
        
        button = new JButton( "Plot Firing Times" ) ;
        button.setActionCommand( "graph firing" ) ;
        button.addActionListener( this ) ;
        menuPane.add( button ) ;
        
        button = new JButton( "Graph Active Neurons vs Time" ) ;
        button.setActionCommand( "num active" ) ;
        button.addActionListener( this ) ;
        menuPane.add( button ) ;
        
        button = new JButton( "Get Average Distances" ) ;
        button.setActionCommand( "avg dist" ) ;
        button.addActionListener( this ) ;
        menuPane.add( button ) ;
        
        button = new JButton( "Synapse Counts" ) ;
        button.setActionCommand( "syn count" ) ;
        button.addActionListener( this ) ;
        menuPane.add( button ) ;
        
        button = new JButton( "Plot Synapse Strength" ) ;
        button.setActionCommand( "plot syn strength" ) ;
        button.addActionListener( this ) ;
        menuPane.add( button ) ;
        
        button = new JButton( "List Synchronized Neurons" ) ;
        button.setActionCommand( "list synchronized" ) ;
        button.addActionListener( this ) ;
        menuPane.add( button ) ;
        
        button = new JButton( "Analyzer Parameters" ) ;
        button.setActionCommand( "params" ) ;
        button.addActionListener( this ) ;
        menuPane.add( button ) ;
        
        content.add( menuPane , BorderLayout.LINE_START ) ;
        content.add( textPane , BorderLayout.CENTER ) ;
        
        window.getContentPane().add( content ) ;
        window.pack( ) ;
        window.setVisible( true ) ;
        
        disp( showMostCorrelated( ) ) ;
        println( "There are " + numSynchronized( ) + " synchronized neurons." ) ;
    }
    
    private void graphFiringCommand( ) {
        try{
            int t1 = getInt( "t start" , 0 , neurons[0].getTime( ) ) ;
            int t2 = getInt( "t stop" , t1 , neurons[0].getTime( ) ) ;
            graphFiring( t1 , t2 ) ;
        } catch ( CancelClicked e ) {
            return ;}
    }
    
    public void actionPerformed( ActionEvent event ) {
        String command = event.getActionCommand( ) ;
        String filename ;
        
        try {
            if ( command.equals( "close" ) ) {
                if ( experimenter != null ) {
                    experimenter.enableGo( ) ;
                }
                window.dispose( ) ;
            } else if ( command.equals( "csv" ) ) {
                filename = getString( "Filename:" , "experiment.csv" ) ;
                if ( filename != null ) {
                    saveExperimentAsCSV( e , filename ) ;
                }
            } else if ( command.equals( "examine" ) ) {
                examineANeuron( ) ;
            } else if ( command.equals( "new graph" ) ) {
                makeNewWindow( ) ;
            } else if ( command.equals( "num active" ) ) {
                graphNumActive( ) ;
            } else if ( command.equals( "avg dist" ) ) {
                showAvgDist( ) ;
            } else if ( command.equals( "syn count" ) ) {
                showSynCount( ) ;
            } else if ( command.equals( "plot syn strength" ) ) {
                showSynapticStrengthGraph( ) ;
            } else if ( command.equals( "params" ) ) {
                setParameters( ) ;
            } else if ( command.equals( "list synchronized" ) ) {
                listSynchronizedNeurons( ) ;
            } else if ( command.equals( "graph firing" ) ) {
                graphFiringCommand( ) ;
            }
        } catch ( Exception e ) {
        }
    }
    
    public void setExperimenter( Experimenter experimenter ) {
        this.experimenter = experimenter ;
    }
    
    public String getParam( String name ) {
        if ( name.equals( "Firing Threshold" ) ) {
            return "" + FIRING_THRESHOLD ;
        } else if ( name.equals( "Synchronization Threshold" ) ) {
            return "" + SYNC_THRESHOLD ;
        } else {
            return null ;
        }
    }
    
    public void setParam( String name , String data ) {
        double value ;
        
        // all parameters are doubles or ints
        try {
            value = Double.parseDouble( data ) ;
        } catch ( NumberFormatException e ) {
            // not a double; ignore the set request
            return ;
        }
        if ( name.equals( "Firing Threshold" ) ) {
            FIRING_THRESHOLD = value ;
        } else if ( name.equals( "Synchronization Threshold" ) ) {
            SYNC_THRESHOLD = value ;
        }
    }
    
    ExperimentAnalyzer( INeuralNetExperiment e ) {
        String [ ] params = { "Firing Threshold" , "Synchronization Threshold" } ;
        LinkedList<INeuron> neurons = e.getNeurons( ) ;
        int i ;
        this.e = e ;
        this.neurons = new INeuron [ neurons.size( ) ] ;
        i = 0 ;
        for	( INeuron n : neurons ) {
            this.neurons [ i ] = n ;
            i ++ ;
        }
        parameterNames = params ;
    }
}
